package neatlogic.module.change.api.sop;

import neatlogic.framework.asynchronization.threadlocal.UserContext;
import neatlogic.framework.auth.core.AuthAction;
import neatlogic.framework.change.dto.*;
import neatlogic.framework.common.constvalue.ApiParamType;
import neatlogic.framework.common.constvalue.GroupSearch;
import neatlogic.framework.common.dto.BasePageVo;
import neatlogic.framework.dto.FieldValidResultVo;
import neatlogic.framework.restful.constvalue.OperationTypeEnum;
import neatlogic.framework.restful.annotation.*;
import neatlogic.framework.restful.core.IValid;
import neatlogic.framework.restful.core.privateapi.PrivateApiComponentBase;
import neatlogic.framework.change.auth.label.CHANGE_MODIFY;
import neatlogic.module.change.dao.mapper.ChangeMapper;
import neatlogic.module.change.dao.mapper.ChangeTemplateMapper;
import neatlogic.framework.change.exception.ChangeParamNotFoundException;
import neatlogic.framework.change.exception.ChangeSopIsReferencedException;
import neatlogic.framework.change.exception.ChangeSopNameRepeatException;
import neatlogic.framework.change.exception.ChangeSopNotFoundException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
@Transactional
@OperationType(type = OperationTypeEnum.CREATE)
@AuthAction(action = CHANGE_MODIFY.class)
public class ChangeSopSaveApi extends PrivateApiComponentBase {
    
    @Resource
    private ChangeTemplateMapper changeTemplateMapper;
    
    @Resource
    private ChangeMapper changeMapper;

    @Override
    public String getToken() {
        return "change/sop/save";
    }

    @Override
    public String getName() {
        return "保存变更sop模板";
    }

    @Override
    public String getConfig() {
        return null;
    }
    @Input({
        @Param(name = "id", type = ApiParamType.LONG, desc = "变更sop模板id"),
        @Param(name = "name", type = ApiParamType.STRING, isRequired = true, desc = "名称"),
        @Param(name = "isActive", type = ApiParamType.ENUM, rule = "0,1", isRequired = true, desc = "是否激活(0,1)"),
        @Param(name = "authority", type = ApiParamType.STRING, desc = "分组uuid，格式：team#uuid"),
        @Param(name = "type", type = ApiParamType.STRING, desc = "类型"),
        @Param(name = "changeSopStepList", type = ApiParamType.JSONARRAY, desc = "步骤列表")
    })
    @Output({
        @Param(name = "id", type = ApiParamType.LONG, desc = "变更sop模板id")
    })
    @Description(desc = "保存变更sop模板")
    @Override
    public Object myDoService(JSONObject jsonObj) throws Exception {
        ChangeSopVo changeSopVo = JSON.toJavaObject(jsonObj, ChangeSopVo.class);
        if(changeTemplateMapper.checkChangeSopNameIsRepeat(changeSopVo) > 0) {
            throw new ChangeSopNameRepeatException(changeSopVo.getName());
        }
        Long id = jsonObj.getLong("id");
        if(id != null) {
            if(changeTemplateMapper.checkChangeSopIsExists(id) == 0) {
                throw new ChangeSopNotFoundException(id);
            }
            /** 变更sop模板被引用后，不能禁用 **/
            if(changeSopVo.getIsActive() == 0){
                List<Long> changeTemplateIdList = changeTemplateMapper.getChangeTemplateIdListByChangeSopId(id);
                if(CollectionUtils.isNotEmpty(changeTemplateIdList)) {
                    throw new ChangeSopIsReferencedException(changeSopVo.getName());
                }
            }
            changeTemplateMapper.deleteChangeSopStepByChangeSopId(id);
            changeTemplateMapper.deleteChangeSopStepUserByChangeSopId(id);
            changeTemplateMapper.deleteChangeSopStepTeamByChangeSopId(id);
            changeTemplateMapper.deleteChangeSopStepContentByChangeSopId(id);
            changeTemplateMapper.deleteChangeSopStepFileByChangeSopId(id);
            changeTemplateMapper.deleteChangeSopStepParamByChangeSopId(id);
            changeSopVo.setLcu(UserContext.get().getUserUuid(true));
            changeTemplateMapper.updateChangeSopById(changeSopVo);
        }else {
            changeSopVo.setFcu(UserContext.get().getUserUuid(true));
            changeTemplateMapper.insertChangeSop(changeSopVo);
        }
        
        List<String> changeParamNameList = new ArrayList<>();
        Map<String, Long> changeParamIdMap = new HashMap<>();
        BasePageVo basePageVo = new BasePageVo();
        basePageVo.setNeedPage(false);
        List<ChangeParamVo> changeParamList = changeTemplateMapper.getChangeParamList(basePageVo);
        for(ChangeParamVo changeParamVo : changeParamList) {
            changeParamNameList.add(changeParamVo.getName());
            changeParamIdMap.put(changeParamVo.getName(), changeParamVo.getId());
        }
        List<ChangeSopStepVo> ChangeSopStepList = changeSopVo.getChangeSopStepList();
        ChangeSopStepList.sort((e1, e2) -> e1.getCode().compareToIgnoreCase(e2.getCode()));
        for (ChangeSopStepVo changeSopStepVo : ChangeSopStepList) {
            /** 保存步骤信息 **/
            changeSopStepVo.setChangeSopId(changeSopVo.getId());
            changeTemplateMapper.insertChangeSopStep(changeSopStepVo);
            /** 保存描述内容 **/
            if (StringUtils.isNotBlank(changeSopStepVo.getContent())) {
                /** 扫描描述内容中的变量，建立变量引用关系 **/
                List<String> refParamList = getReferenceChangeParamList(changeSopStepVo.getContent());
                for(String paramName : refParamList) {
                    if(changeParamNameList.contains(paramName)) {
                        changeTemplateMapper.insertChangeSopStepParam(new ChangeSopStepParamVo(changeSopVo.getId(), changeSopStepVo.getUuid(), changeParamIdMap.get(paramName)));
                    }else {
                        throw new ChangeParamNotFoundException(paramName);
                    }
                }
                ChangeContentVo contentVo = new ChangeContentVo(changeSopStepVo.getContent());
                changeMapper.replaceChangeContent(contentVo);
                changeTemplateMapper.insertChangeSopStepContent(new ChangeSopStepContentVo(changeSopVo.getId(), changeSopStepVo.getUuid(),
                    contentVo.getHash()));
            }
            /** 保存附件 **/
            if (CollectionUtils.isNotEmpty(changeSopStepVo.getFileIdList())) {
                for (Long fileId : changeSopStepVo.getFileIdList()) {
                    changeTemplateMapper.insertChangeSopStepFile(new ChangeSopStepFileVo(changeSopVo.getId(), changeSopStepVo.getUuid(),
                        fileId));
                }
            }
            /** 保存处理人或组 **/
            String worker = changeSopStepVo.getWorker();
            if (StringUtils.isNotBlank(worker) && worker.contains("#")) {
                String[] split = worker.split("#");
                if (GroupSearch.USER.getValue().equals(split[0])) {
                    changeTemplateMapper.insertChangeSopStepUser(
                        new ChangeSopStepUserVo(changeSopVo.getId(), changeSopStepVo.getUuid(), split[1]));
                } else if (GroupSearch.TEAM.getValue().equals(split[0])) {
                    changeTemplateMapper.insertChangeSopStepTeam(
                        new ChangeSopStepTeamVo(changeSopVo.getId(), changeSopStepVo.getUuid(), split[1]));
                }
            }
        }
        return changeSopVo.getId();
    }

    public IValid name(){
        return value -> {
            ChangeSopVo changeSopVo = JSON.toJavaObject(value,ChangeSopVo.class);
            if (changeTemplateMapper.checkChangeSopNameIsRepeat(changeSopVo) > 0) {
                return new FieldValidResultVo(new ChangeSopNameRepeatException(changeSopVo.getName()));
            }
            return new FieldValidResultVo();
        };
    }

    private List<String> getReferenceChangeParamList(String content){
        Set<String> resultSet = new HashSet<>();
        String prefix = "${DATA.";
        String suffix = "}";
        int fromIndex = 0;
        int length = content.length();
        while(fromIndex < length) {
            int prefixIndex = content.indexOf(prefix, fromIndex);
            if(prefixIndex == -1) {
                break;
            }
            fromIndex = prefixIndex + prefix.length();
            int suffixIndex = content.indexOf(suffix, fromIndex);
            if(suffixIndex == -1) {
                break;
            }
            resultSet.add(content.substring(fromIndex, suffixIndex));
            fromIndex = suffixIndex + suffix.length();
        }
        return new ArrayList<String>(resultSet);
    }
}
